package io.adrainty.bolee.framework.redis.resolver;

import cn.hutool.core.collection.CollUtil;
import io.adrainty.bolee.framework.commons.user.DataSecurityEntity;
import io.adrainty.bolee.framework.commons.user.SubjectContentUtil;
import io.adrainty.bolee.framework.redis.properties.DataSecurityCacheProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;

import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * <p>FrameworkRedisCacheManager</p>
 *
 * @author AdRainty
 * @version V1.0.0
 * @description FrameworkRedisCacheManager
 * @since 2025/8/1 15:39:31
 */
public class FrameworkRedisCacheManager extends RedisCacheManager {

    private final DataSecurityCacheProperties tenantCacheProperties;

    public FrameworkRedisCacheManager(RedisConnectionFactory redisConnectionFactory,
                                      RedisCacheConfiguration cacheConfiguration,
                                      DataSecurityCacheProperties properties) {
        super(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), cacheConfiguration);
        this.tenantCacheProperties = properties;
    }

    /**
     * 创建缓存
     *
     * @param name        缓存名称
     * @param cacheConfig 缓存配置
     * @return RedisCache
     */
    @Nonnull
    @Override
    protected RedisCache createRedisCache(@Nonnull String name, RedisCacheConfiguration cacheConfig) {
        String[] nameSplit = name.split("&");
        if (nameSplit.length == 2) {
            name = nameSplit[0];
            long ttl = Long.parseLong(nameSplit[1].replace("ttl=", ""));
            cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
        } else if (nameSplit.length != 1) {
            throw new IllegalArgumentException("Invalid cache name: " + name + ". Usage: name or name@ttl (seconds)");
        }

        return new FrameworkRedisCache(name, this.getCacheWriter(), cacheConfig);
    }

    /**
     * 获取缓存, 从上下文中获取租户ID, 重写key值添加多租户模式
     *
     * @param name 缓存名称
     * @return Cache
     */
    @Nonnull
    @Override
    public Cache getCache(@Nonnull String name) {
        // 多租户及数据权限缓存key处理
        String companyNo = SubjectContentUtil.getCompanyNo();
        String dataSecurity = null;
        DataSecurityEntity dataSecurityVO = SubjectContentUtil.getDataSecurityVO();
        // 查看个人数据
        if (Objects.nonNull(dataSecurityVO) && dataSecurityVO.getYourselfData()) {
            dataSecurity = String.valueOf(SubjectContentUtil.getUserVO().getId().hashCode());
        }
        // 查看授权数据
        if (Objects.nonNull(dataSecurityVO) && !dataSecurityVO.getYourselfData()) {
            dataSecurity = dataSecurity + ":" + SubjectContentUtil.getUserVO().getDataSecurityVO().hashCode();
        }
        String[] nameTime = name.split("&");
        String targetTab = "tab_" + name.split(":")[0].replace("-", "_");
        if (StringUtils.isNotBlank(companyNo) &&
                !tenantCacheProperties.getDefaultCompanyNo().equals(companyNo)) {
            boolean isIgnoreCompanyNo = false;
            if (CollUtil.isNotEmpty(tenantCacheProperties.getIgnoreCompanyTables())) {
                isIgnoreCompanyNo = !tenantCacheProperties.getIgnoreCompanyTables().contains(targetTab);
            }
            if (isIgnoreCompanyNo) {
                nameTime[0] = nameTime[0] + ":" + companyNo;
            }
        }
        boolean isIgnoreDataSecurity = false;
        if (CollUtil.isNotEmpty(tenantCacheProperties.getIgnoreDataSecurityTables())) {
            isIgnoreDataSecurity = !tenantCacheProperties.getIgnoreDataSecurityTables().contains(targetTab);
        }
        if (isIgnoreDataSecurity) {
            nameTime[0] = nameTime[0] + ":" + dataSecurity;
        }
        if (nameTime.length == 2) {
            name = nameTime[0] + "&" + nameTime[1];
        } else {
            name = nameTime[0];
        }
        // 默认企业则不做缓存租户处理
        return Objects.requireNonNull(super.getCache(name));
    }

    @Override
    @Nonnull
    public Map<String, RedisCacheConfiguration> getCacheConfigurations() {
        Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>(getCacheNames().size());
        getCacheNames().forEach(it -> {
            RedisCache cache = (FrameworkRedisCache) lookupCache(it);
            configurationMap.put(it, cache != null ? cache.getCacheConfiguration() : null);
        });
        return Collections.unmodifiableMap(configurationMap);
    }

}
